package com.settlement.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import com.settlement.system.common.constant.CommonConstant;
import com.settlement.system.common.enums.AccountStatusEnum;
import com.settlement.system.common.enums.CommonCode;
import com.settlement.system.common.enums.NcAccountStatusEnum;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.common.util.common.*;
import com.settlement.system.mapper.BaseMapper;
import com.settlement.system.mapper.TblNcVurcherDetailPlusMapper;
import com.settlement.system.mapper.security.userdetails.SysUserDetails;
import com.settlement.system.model.dto.*;
import com.settlement.system.model.entity.common.SystemUser;
import com.settlement.system.model.entity.common.TblAssistItemConfig;
import com.settlement.system.model.entity.common.TblNcVurcherDetailPlus;
import com.settlement.system.model.entity.common.TblReceiveRefundEditor;
import com.settlement.system.model.vo.MsgResultVo;
import com.settlement.system.service.ITblAssistItemConfigService;
import com.settlement.system.service.ITblNcVurcherDetailPlusService;
import com.settlement.system.service.ITblNcVurcherNoRecordService;
import com.settlement.system.service.ITblReceiveRefundEditorService;
import com.settlement.system.service.kafka.producer.AcsKafkaProducer;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.settlement.system.common.enums.NcAccountStatusEnum.*;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

/**
 * NC凭证明细_优化 服务实现类
 * @author xiaochuan
 * @since 2021-01-20
 */
@Slf4j
@Service
public class TblNcVurcherDetailPlusServiceImpl extends BaseServiceImpl implements ITblNcVurcherDetailPlusService {

    @Resource
    private TblNcVurcherDetailPlusMapper tblNcVurcherDetailPlusMapper;

    @Resource
    private ITblReceiveRefundEditorService tblReceiveRefundEditorService;

    @Resource
    private ITblAssistItemConfigService tblAssistItemConfigService;

    @Resource
    private ITblNcVurcherDetailPlusService tblNcVurcherDetailPlusService;

    @Resource
    private ITblNcVurcherNoRecordService tblNcVurcherNoRecordService;

    @Resource
    AcsKafkaProducer acsKafkaProducer;

    @Value("${spring.kafka.topic.push-nc}")
    public String pushNcTopic;
    @Value("${fsp.tokenSecrect}")
    private String tokenSecrect;
    @Value("${fsp.outterSys}")
    private String outterSys;
    @Value("${fsp.deleteVoucherURL}")
    private String deleteVoucherURL;
    @Value("${fsp.menu}")
    private String menu;

    /*@Reference(version = "${dubbo.acs.api.version}", timeout = 6000)
    private RrPushNcApi rrPushNcApi;*/

    @Override
    public BaseMapper init() {
        return tblNcVurcherDetailPlusMapper;
    }

    @Override
    public TblNcVurcherDetailPlus getFoot(Map<String, Object> params) throws ServiceException {
        try {
            return tblNcVurcherDetailPlusMapper.getFoot(params);
        } catch (Exception ex){
            log.error("获取合计异常",ex);
            throw new ServiceException("获取合计异常",ex);
        }
    }

    @Override
    public String revokeNc(Map<String, Object> params) throws ServiceException {
        try {
            // 先找出本账户对应的editNo
            SysUserDetails user = SecurityUtils.getUser();;
            String username = user.getUsername();
            TblReceiveRefundEditor editor = tblReceiveRefundEditorService.getEditorByLoginName(username);

            // 当前用户不是制单人身份，提示"撤销人非制单人，故无法撤销！"
            if(editor==null){
                return "撤销人非制单人，故无法撤销！";
            }
            String editorNo = editor.getEditorName();

            // 再看 editNo 不符合本editNo的NC凭证条数，如果大于0，那么返回
            params.put("notEditorName",editorNo);
            FasUtil.formatInQueryCondition(params,"editorName","companyNo","summaryId");
            if(tblNcVurcherDetailPlusMapper.selectCount(params) > 0){
                return "选中了制单人不是当前用户的数据,不能执行撤销操作";
            }
            // 去掉参数
            params.remove("notEditorName");
            if(tblNcVurcherDetailPlusMapper.selectCount(params) == 0){
                return "没有选中的数据,不能执行撤销操作";
            }

            List<Integer>permitNcAccountStatusList = new ArrayList<>();
            permitNcAccountStatusList.add(NcAccountStatusEnum.NOT_PUSH.code());
            permitNcAccountStatusList.add(NcAccountStatusEnum.PUSH_FAIL.code());
            List<Integer> accountStatusList = tblNcVurcherDetailPlusMapper.selectAccountStatus(params);
            if(!CollectionUtils.isEmpty(accountStatusList)){
                for (Integer pushFasStatus : accountStatusList) {
                    if(!permitNcAccountStatusList.contains(pushFasStatus)){
                        return "只有单据[记账状态]为：\"未推送NC\"、或 \"推送NC失败\"的才能操作撤销。";
                    }
                }
            }

            tblNcVurcherDetailPlusMapper.updateAccountStatusOfSummary(
                    FasUtil.formatInQueryCondition(AccountStatusEnum.T2_HAS_CREATED.getNo()+","+AccountStatusEnum.T6_PUSH_NC_FAILED.getNo()),
                    AccountStatusEnum.T3_REVOKE_CREATED.getNo(),
                    params
            );

            tblNcVurcherDetailPlusMapper.updateAccountStatusOfCostShare(
                    FasUtil.formatInQueryCondition(AccountStatusEnum.T2_HAS_CREATED.getNo()+","+AccountStatusEnum.T6_PUSH_NC_FAILED.getNo()),
                    AccountStatusEnum.T3_REVOKE_CREATED.getNo(),
                    params
            );
            /*rrPushNcApi.revokeNcPlus(params);*/
        } catch (Exception ex){
            log.error("撤销NC异常", ex);
            throw new ServiceException("撤销NC异常", ex);
        }
        return null;
    }

    private boolean checkSameMonth(String dateOneStr,String dateTwoStr) {
        try {
            Date dateOne = DateUtil.getDate(dateOneStr, "yyyy-MM");
            Date dateTwo = DateUtil.getDate(dateTwoStr, "yyyy-MM");
            return dateOne.compareTo(dateTwo)==0;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public String checkPush(Map<String, Object> params) throws ServiceException {
        String startOutDate = (String) params.get("startOutDate");
        String endOutDate = (String) params.get("endOutDate");
        if(StringUtils.isNoneEmpty(startOutDate,endOutDate)){
            //boolean isSameMonth = startOutDate.substring(0,7).equals(endOutDate.substring(0,7));
            boolean isSameMonth = checkSameMonth(startOutDate,endOutDate);
            if(!isSameMonth){
                return "点击[推送NC]时，[制单日期]起始日期和终止日期 必须在同一个自然月份";
            }
        }

        // 先找出本账户对应的editNo
        SysUserDetails user = SecurityUtils.getUser();;
        String username = user.getUsername();
        TblReceiveRefundEditor editor = tblReceiveRefundEditorService.getEditorByLoginName(username);
        // 当前用户不是制单人身份，提示"推送NC人非制单人，故无法推送NC！"
        if(ObjectUtil.isNull(editor)){
            return "推送NC人非制单人，故无法推送NC！";
        }
        List<TblNcVurcherDetailPlus> detailPlusList = this.tblNcVurcherDetailPlusMapper.selectByParam(params);
        if(CollectionUtils.isEmpty(detailPlusList)){
            return "推送NC数据不存在！";
        }
        // 判断当前数据是否全部为当前制单人，否则不允许推送
        boolean notEdit = detailPlusList.stream().allMatch(v -> editor.getEditorName().equals(v.getEditorNo()));
        if(!notEdit){
            return "操作推送人与[制单人]必须是同一用户";
        }
        boolean notPush = detailPlusList.stream().anyMatch(v -> !EnumUtil.in(v.getAccountStatus(), NOT_PUSH, PUSH_FAIL));
        if(notPush){
            return "[记账状态]为未推送NC或推送NC失败的明细才能操作推送NC！";
        }
        boolean notPushData = detailPlusList.stream().allMatch(v -> EnumUtil.eq(v.getAccountStatus(), NOT_PUSH));
        boolean pushFailData = detailPlusList.stream().allMatch(v -> EnumUtil.eq(v.getAccountStatus(), PUSH_FAIL));
        final boolean notVurcherNumber = detailPlusList.stream().anyMatch(v -> v.getVurcherNumber() == null);
        if(!notPushData && !pushFailData){
            return "未推送NC和推送NC失败,两种状态的数据需要分开推送,请重新筛选！";
        }
        //全部为未推送NC状态的数据推送NC
        if(notPushData || notVurcherNumber){
            return StrUtil.append(NOT_PUSH.code());
        }
        //全部为推送NC失败状态的数据推送NC
        return StrUtil.append(PUSH_FAIL.code());
    }

    @Override
    public String pushNc(Map<String, Object> params) {
        //获取本次需要推出的NC数据
        List<TblNcVurcherDetailPlus> detailPlusList = this.tblNcVurcherDetailPlusMapper.findPushNcByParam(params);
        if(CollectionUtils.isEmpty(detailPlusList)){
            return "没有可以推送的凭证明细数据！";
        }
        MsgResultVo msgResultVo=MsgResultVo.newInstance();
        detailPlusList.forEach(v->this.checkRequiredField(v,msgResultVo));
        if(msgResultVo.isResult()){
            Integer startVoucherNo= MapUtils.getInteger(params,"startVoucherNo");
            //根据起始凭证号计算分配凭证号
            this.calculateVoucherNo(detailPlusList,startVoucherNo);
            this.sendNcVoucher(detailPlusList,msgResultVo);
        }else {
            log.info("推送NC凭证失败,更新本次推送为推送失败！");
            detailPlusList.forEach(detail -> {
                detail.setAccountStatus(PUSH_FAIL.code());
            });
            BaseConsumer.batchData(detailPlusList, tblNcVurcherDetailPlusMapper::batchUpdateById);
        }
        return msgResultVo.getMessage();
    }

    @Override
    public void updateByOrderNo(TblNcVurcherDetailPlus vurcherDetail) {
        this.tblNcVurcherDetailPlusMapper.updateByOrderNo(vurcherDetail);
    }

    @Override
    public void updateBySerialNo(TblNcVurcherDetailPlus vurcherDetail) {
        this.tblNcVurcherDetailPlusMapper.updateBySerialNo(vurcherDetail);
    }

    @Override
    public void updateNcVoucherNoBySerialNo(String ncVoucherNo,String orderNo) {
        this.tblNcVurcherDetailPlusMapper.updateNcVoucherNoBySerialNo(ncVoucherNo,orderNo);
    }

    @Override
    public void updateAccountStatusOfCostAllocationBySerialNo(String serialNo,String toAccountStatus,String accountFailDesc) {
        this.tblNcVurcherDetailPlusMapper.updateAccountStatusOfCostAllocationBySerialNo(serialNo,toAccountStatus,accountFailDesc);
    }

    @Override
    public void updateAccountStatusOfUnificationSummaryBySerialNo(String serialNo,String toAccountStatus,String accountFailDesc) {
        this.tblNcVurcherDetailPlusMapper.updateAccountStatusOfUnificationSummaryBySerialNo(serialNo,toAccountStatus,accountFailDesc);
    }

    @Override
    public String deletePushNc(Map<String, Object> params) throws ServiceException {
        log.info("撤销推送NC凭证开始-----参数：{}", JSONUtil.toJsonStr(params));
        // 先找出本账户对应的editNo
        SysUserDetails user = SecurityUtils.getUser();;
        String username = user.getUsername();
        TblReceiveRefundEditor editor = tblReceiveRefundEditorService.getEditorByLoginName(username);
        // 当前用户不是制单人身份，提示"推送NC人非制单人，故无法推送NC！"
        if(ObjectUtil.isNull(editor)){
            return "撤销推送NC人非制单人，故无法撤销推送NC！";
        }
        List<TblNcVurcherDetailPlus> detailPlusList = this.tblNcVurcherDetailPlusMapper.selectByParam(params);
        if(CollectionUtils.isEmpty(detailPlusList)){
            return "撤销推送NC数据不存在！";
        }
        // 判断当前数据是否全部为当前制单人，否则不允许推送
        boolean notEdit = detailPlusList.stream().allMatch(v -> v.getEditorNo().equals(editor.getEditorName()));
        if(!notEdit){
            return "操作撤销人与[制单人]必须是同一用户";
        }
        boolean notDeletePush = detailPlusList.stream().anyMatch(v -> !EnumUtil.in(v.getAccountStatus(), PUSH_SUCC, BACKOUT_FAIL,ANNEX_COL_SUCC,ANNEX_COL_FAIL));
        if(notDeletePush){
            return "[记账状态]为推送NC成功、撤销推送失败、附件归集成功或者附件归集失败的明细才能操作[撤销推送]";
        }
        return tblNcVurcherDetailPlusService.doDeletePushNc(detailPlusList,editor.getEditorName());
    }
    /**
     * 处理撤销NC凭证方法
     * @param detailPlusList 撤销凭证列表
     * @param editorNo 制单人
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String doDeletePushNc(List<TblNcVurcherDetailPlus> detailPlusList, String editorNo) {
        //获取撤销推送流水号列表
        Set<String> serialNos = detailPlusList.stream().map(TblNcVurcherDetailPlus::getSerialNo).collect(toSet());
        log.info("开始撤销NC凭证，制单人：{}，批次流水号列表：{}----开始", editorNo, JSONUtil.toJsonStr(serialNos));
        final StringBuilder builder = new StringBuilder("");
        serialNos.forEach(serialNo -> {
            String accessToken = DigestUtils.md5DigestAsHex(StrUtil.append(serialNo, editorNo, tokenSecrect).getBytes());
            Map<String, Object> paramMap = Maps.newHashMap();
            paramMap.put("access_token", accessToken);
            paramMap.put("serial_no", serialNo);
            paramMap.put("source_bill_maker", editorNo);
            log.info("请求FSP撤销凭证号开始，url={},撤销流水号serialNo={},请求参数requstJosn={}",deleteVoucherURL, serialNo, JSONUtil.toJsonStr(paramMap));
            String result = HttpUtil.post(deleteVoucherURL, JsonUtil.getJsonOrToString(paramMap));
            if(!JSONUtil.isJson(result)){
                StrUtil.append(builder,"请求FSP撤销凭证接口出现异常！");
                return;
            }
            DelVoucherFspResultDto resultDto = JSONUtil.toBean(result, DelVoucherFspResultDto.class);
            TblNcVurcherDetailPlus detailPlus=new TblNcVurcherDetailPlus();
            detailPlus.setSerialNo(serialNo);
            detailPlus.setUpdateUser(editorNo);
            if (resultDto.isResult()) {
                log.info("请求FSP撤销凭证号成功，推送流水号serialNo={},返回参数resultJosn={}", serialNo, result);
                detailPlus.setAccountStatus(NcAccountStatusEnum.NOT_PUSH.code());
                detailPlus.setPkVurcher("clean");
                //根据推送批次号更新凭证明细状态为未推送
                tblNcVurcherDetailPlusMapper.updateBySerialNo(detailPlus);
                tblNcVurcherDetailPlusMapper.updateNcVoucherNoBySerialNo("",detailPlus.getSerialNo());
                tblNcVurcherDetailPlusMapper.updateAccountStatusOfCostAllocationBySerialNo(detailPlus.getSerialNo(),AccountStatusEnum.T2_HAS_CREATED.getNo(),"");
                tblNcVurcherDetailPlusMapper.updateAccountStatusOfUnificationSummaryBySerialNo(detailPlus.getSerialNo(),AccountStatusEnum.T2_HAS_CREATED.getNo(),"");
                log.info("更新凭证明细状态为未推送成功，推送流水号serialNo={}", JSONUtil.toJsonStr(serialNo));
            } else {
                log.info("请求FSP撤销凭证号失败，撤销流水号serialNo={},返回参数resultJosn={}", serialNo, result);
                detailPlus.setAccountStatus(NcAccountStatusEnum.BACKOUT_FAIL.code());
                detailPlus.setFailDesc(resultDto.getMessage());
                tblNcVurcherDetailPlusMapper.updateBySerialNo(detailPlus);
            }
        });
        return builder.toString();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateNcVoucherNo(Map<String, Object> params) {
        FasUtil.formatInQueryCondition(params, "editorName", "companyNo", "summaryId","vurcherNumber");
        Integer count = tblNcVurcherDetailPlusMapper.selectCount(params);
        AssertUtil.mustTrue(count > 0,"查询数据为空，无需获取NC凭证号!");
        //保存操作日志
        NcVoucherNoDto dto=tblNcVurcherNoRecordService.saveRecord(params);
        /*AcsResultVo resultVo = rrPushNcApi.asyncUpdateNcVoucherNo(dto);
        AssertUtil.mustTrue(resultVo.isSuccess(),resultVo.getMessage());*/
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void annexCol(Map<String, Object> params) {
        FasUtil.formatInQueryCondition(params, "editorName", "companyNo", "summaryId","vurcherNumber");
        Integer count = tblNcVurcherDetailPlusMapper.selectCount(params);
        AssertUtil.mustTrue(count > 0,"查询数据为空，无需附件归集!");
        //更新凭证明细状态为附件归集中
        SystemUser systemUser = SystemUserUtil.getSystemUser();
        params.put("updateUser",systemUser.getUsername());
        NcVoucherNoDto dto = BeanUtil.toBean(params, NcVoucherNoDto.class);
        /*AcsResultVo resultVo = rrPushNcApi.asyncAnnexCol(dto);
        AssertUtil.mustTrue(resultVo.isSuccess(),resultVo.getMessage());*/
    }

    /**
     * 推送NC数据
     * @param detailPlusList 凭证明细
     * @return 推送NC数据
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void sendNcVoucher(List<TblNcVurcherDetailPlus> detailPlusList,MsgResultVo msgResultVo) {
        //根据流水号对凭证明细进行分组推送
       detailPlusList.stream().filter(Objects::nonNull)
                .collect(Collectors.groupingBy(TblNcVurcherDetailPlus::getSerialNo))
                .entrySet().stream().forEach(v->{
                        List<TblNcVurcherDetailPlus> vurcherDetails = v.getValue();
                        TblNcVurcherDetailPlus detailPlus = vurcherDetails.stream().findFirst().orElse(null);
                        VoucherMessageDto messageDto=new VoucherMessageDto();
                        messageDto.setSerial_no(detailPlus.getSerialNo());
                        messageDto.setAccountingbook_code(detailPlus.getNcCheckAccountBookNo());
                        messageDto.setOutter_sys(outterSys);
                        messageDto.setMenu(menu);
                        messageDto.setDept_flag("FAS-ACS");
                        MsgResultVo resultVo=MsgResultVo.newInstance();
                        messageDto.setData(this.getVoucherData(vurcherDetails,resultVo));
                       if(resultVo.isResult()){
                           BaseConsumer.batchData(vurcherDetails, tblNcVurcherDetailPlusMapper::batchUpdateById);
                           log.info("推送NC凭证serialNo={},更新本地推送数据记账状态为推送中完成",detailPlus.getSerialNo());
                           acsKafkaProducer.sendMessage(pushNcTopic, messageDto);
                       }else {
                           vurcherDetails.forEach(detail -> {
                               detail.setAccountStatus(PUSH_FAIL.code());
                               detail.setVurcherNumber(null);
                           });
                           BaseConsumer.batchData(vurcherDetails, tblNcVurcherDetailPlusMapper::batchUpdateById);
                           msgResultVo.setResult(false);
                           msgResultVo.setMessage("推送NC凭证失败,具体错误请参考失败原因");
                       }
                });
    }

    /**
     * 获取推送NC凭证data数据
     * @param vurcherDetails 凭证明细
     * @return NC凭证data数据
     */
    private List<VoucherData> getVoucherData(List<TblNcVurcherDetailPlus> vurcherDetails, MsgResultVo msgResultVo) {
        List<VoucherData> voucherDataList=Lists.newArrayList();
        TblNcVurcherDetailPlus vurcherDetail=vurcherDetails.stream().findFirst().orElse(new TblNcVurcherDetailPlus());
        VoucherData voucherData=new VoucherData();
        voucherData.setIscheck(false);
        voucherData.setOrder_no(vurcherDetail.getOrderNo());
        voucherData.setSource_bill_maker(vurcherDetail.getEditorNo());
        voucherData.setBill_date(DateUtil.formatDate(vurcherDetail.getEditorDate()));
        voucherData.setVoucher_no(vurcherDetail.getVurcherNumber());
        AtomicInteger index = new AtomicInteger(1);
        List<VoucherDetail> details = vurcherDetails.stream().map(this.getVoucherDetailFunction(index,msgResultVo)).collect(toList());
        voucherData.setDetails(details);
        voucherDataList.add(voucherData);
        return voucherDataList;
    }

    /**
     * 获取凭证明细
     * @param index 行号
     * @return Function
     */
    private Function<TblNcVurcherDetailPlus, VoucherDetail> getVoucherDetailFunction(AtomicInteger index,MsgResultVo msgResultVo) {
        return v -> {
            VoucherDetail detail = new VoucherDetail();
            detail.setRownum(index.getAndIncrement());
            detail.setAccasoa_code(v.getSubjectNo());
            detail.setExplanation(v.getSummary());
            detail.setCurrtype(v.getCoinType());
            detail.setExcrate("1.00");
            //this.checkRequiredField(v,msgResultVo);
            if(v.getTargetCoinBorrowerAmount().compareTo(BigDecimal.ZERO)!=0){
                detail.setLocalamount(v.getTargetCoinBorrowerAmount());
                detail.setDirection(CommonConstant.BORROW_D);
            }else {
                detail.setLocalamount(v.getTargetCoinLoanAmount());
                detail.setDirection(CommonConstant.LOAN_C);
            }
            List<String> sourceIndex = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9");
            List<AitemData> aitems = Lists.newArrayList();
            for (String i : sourceIndex) {
                AitemData aitemData = new AitemData();
                String arithmeticSource = (String) ReflectUtil.getFieldValue(v, "checkArithmeticSource" + i);
                if (StringUtils.isBlank(arithmeticSource)) {
                    //如果第一个为空，就跳出循环
                    break;
                }
                if (StringUtils.isNotBlank(arithmeticSource)) {
                    String checkArithmetic = (String) ReflectUtil.getFieldValue(v, "checkArithmetic" + i);
                    if(StringUtils.startsWith(checkArithmetic,CommonConstant.WAVE)){
                        continue;
                    }
                    if(!StringUtils.contains(checkArithmetic,CommonConstant.COLON)){
                        log.error("辅助项值格式不对，应该是辅助项值和NC辅助核算项名称用【:】隔开!");
                        v.setFailDesc("辅助项值格式不对，应该是辅助项值和NC辅助核算项名称用【:】隔开");
                        v.setAccountStatus(PUSH_FAIL.code());
                        msgResultVo.setResult(false);
                        continue;
                    }

                    String[] splitAitems = checkArithmetic.split(CommonConstant.COLON);
                    //转换辅助项配置
                    TblAssistItemConfig assistItem = tblAssistItemConfigService.selectByNcName(splitAitems[1]);
                    if(ObjectUtil.isNull(assistItem)){
                        log.error(StrUtil.format("NC辅助核算项名称：【%s】,查询辅助项配置表为空！",splitAitems[1]));
                        v.setFailDesc(StrUtil.format("NC辅助核算项名称：【%s】,查询辅助项配置表为空！",splitAitems[1]));
                        v.setAccountStatus(PUSH_FAIL.code());
                        msgResultVo.setResult(false);
                        continue;
                    }
                    aitemData.setAssitem_value(splitAitems[0]);
                    aitemData.setAssitem_code(assistItem.getSsCode());
                    aitemData.setNeed_change(CommonCode.ZERO.code());
                }
                aitems.add(aitemData);
            }
            detail.setAitems(aitems);
            return detail;
        };
    }

    /**
     * 校验必填字段
     * @param detail 凭证明细
     * @param msgResultVo 校验结果
     */
    private void checkRequiredField(TblNcVurcherDetailPlus detail, MsgResultVo msgResultVo) {
        String ncCheckAccountBookNo = StrUtil.notNull(detail::getNcCheckAccountBookNo, x -> StringUtils.isBlank(x), "核算账簿编码");
        String vurcherCategoryNo = StrUtil.notNull(detail::getVurcherCategoryNo, x -> StringUtils.isBlank(x), "凭证类别编码");
        String editorNo = StrUtil.notNull(detail::getEditorNo, x -> StringUtils.isBlank(x), "制单人编码");
        String editorDate = StrUtil.notNull(detail::getEditorDate, x -> x==null, "制单日期");
        String summary = StrUtil.notNull(detail::getSummary, x -> StringUtils.isBlank(x), "摘要");
        String subjectNo = StrUtil.notNull(detail::getSubjectNo, x -> StringUtils.isBlank(x), "科目编码");
        String businessUnitNo = StrUtil.notNull(detail::getBusinessUnitNo, x -> StringUtils.isBlank(x), "业务单元编码");
        String channelNo = StrUtil.notNull(detail::getChannelNo, x -> StringUtils.isBlank(x), "渠道");
        String recordAccountProject = StrUtil.notNull(detail::getRecordAccountProject, x -> StringUtils.isBlank(x), "记账项目");
        String vurcherType = StrUtil.notNull(detail::getVurcherType, x -> StringUtils.isBlank(x), "凭证类型");
        String check = StrUtil.joinNotNullWith(',', ncCheckAccountBookNo, vurcherCategoryNo, editorNo, editorDate,summary,subjectNo,channelNo,
                recordAccountProject,businessUnitNo,vurcherType);
        if(StringUtils.isNotBlank(check)){
            msgResultVo.setResult(false);
            msgResultVo.setMessage("推送NC凭证失败,具体错误请参考失败原因");
            detail.setFailDesc(StrUtil.append("[",check,"]字段为空,请校验！"));
        }
    }

    /**
     * 计算凭证号
     * @param detailPlusList 凭证明细
     * @param startVoucherNo 起始凭证号
     */
    private void calculateVoucherNo(List<TblNcVurcherDetailPlus> detailPlusList, Integer startVoucherNo) {
        log.info(StrUtil.format("计算本次推送NC凭证凭证号开始，起始凭证号：%s",startVoucherNo));
        String serialNo = GenSerialUtil.genSerialNo();
        String orderNo= null;
        for (int i = 0; i < detailPlusList.size(); i++) {
            //存在两条数据，需要比较前后两条数据的[核算账簿]+[制单人]+[制单日期]+[渠道]+[记账项目]+[凭证类型]+，当这6个字段一样时，则合成1个凭证号
            TblNcVurcherDetailPlus detailPlus = detailPlusList.get(i);
            if(i> CommonCode.ZERO.code()){
                //取上一个凭证明细
                TblNcVurcherDetailPlus upDetailPlus = detailPlusList.get(i-1);
                //比较当前凭证明细和上一条凭证明细，是否上面的六个字段是否一样
                if(ObjectUtil.isNull(startVoucherNo)){
                    //推送失败的数据，直接使用自己的凭证号
                    if(!StringUtils.equals(detailPlus.getVurcherNumber(),upDetailPlus.getVurcherNumber())){
                        serialNo = GenSerialUtil.genSerialNo();
                        //生成订单号  "ACS"+[核算账簿]+[会计期间]+至增数字
                        orderNo  = GenSerialUtil.genOrderNo(detailPlus.getNcCheckAccountBookNo(),detailPlus.getEditorDate());
                    }
                }else {
                    if(!this.checkVurcherNo(detailPlus,upDetailPlus)){
                        //凭证号加一
                        ++startVoucherNo;
                        serialNo = GenSerialUtil.genSerialNo();
                        //生成订单号  "ACS"+[核算账簿]+[会计期间]+至增数字
                        orderNo  = GenSerialUtil.genOrderNo(detailPlus.getNcCheckAccountBookNo(),detailPlus.getEditorDate());
                    }
                }
            }
            if(StringUtils.isBlank(orderNo)){
                orderNo = GenSerialUtil.genOrderNo(detailPlus.getNcCheckAccountBookNo(),detailPlus.getEditorDate());
            }
            detailPlus.setSerialNo(serialNo);
            detailPlus.setOrderNo(orderNo);
            detailPlus.setAccountStatus(NcAccountStatusEnum.PUSH_IN.code());
            if(ObjectUtil.isNotNull(startVoucherNo)){
                detailPlus.setVurcherNumber(String.valueOf(startVoucherNo));
            }
            detailPlus.setFailDesc(null);
        }
        log.info(StrUtil.format("计算本次推送NC凭证凭证号结束，结束凭证号：%s",startVoucherNo));
    }

    /**
     * 比较当前凭证明细和上一条凭证明细，是否上面的六个字段是否一样
     * @param detailPlus 当前凭证明细
     * @param upDetailPlus 上一条凭证明细
     * @return 判断结果 true:同一个凭证号 false:凭证号不同
     */
    private boolean checkVurcherNo(TblNcVurcherDetailPlus detailPlus, TblNcVurcherDetailPlus upDetailPlus) {

        if(StringUtils.equals(detailPlus.getNcCheckAccountBookNo(),upDetailPlus.getNcCheckAccountBookNo())
                &&StringUtils.equals(detailPlus.getEditorNo(),upDetailPlus.getEditorNo())
                &&detailPlus.getEditorDate().compareTo(upDetailPlus.getEditorDate())==0
                &&StringUtils.equals(detailPlus.getChannelNo(),upDetailPlus.getChannelNo())
                &&StringUtils.equals(detailPlus.getRecordAccountProject(),upDetailPlus.getRecordAccountProject())
                &&StringUtils.equals(detailPlus.getVurcherType(),upDetailPlus.getVurcherType())){
            return true;
        }
        return false;
    }
}

